/*
 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.lang.invoke;

import java.lang.reflect.*;
import java.util.*;
import java.lang.invoke.MethodHandleNatives.Constants;
import java.lang.invoke.MethodHandles.Lookup;
import static java.lang.invoke.MethodHandleStatics.*;

/**
 * 通过将直接方法句柄分解为其组成符号部分而获得的符号引用。
 * 要分解直接方法句柄，请调用{@link Lookup#revealDirect Lookup.revealDirect}。
 * <h1><a name="directmh"></a>直接方法句柄</h1>
 * <em>直接方法句柄</em>表示方法、构造函数或字段，
 * 没有任何中间参数绑定或其他变换。
 * 直接方法句柄引用的方法、构造函数或字段称为
 * 其<em>底层成员</em>。
 * 直接方法句柄可以通过以下任何方式获得：
 * <ul>
 * <li>通过在{@code CONSTANT_MethodHandle}常量上执行{@code ldc}指令。
 *     （参见Java虚拟机规范，第4.4.8和5.4.3节。）
 * <li>通过调用<a href="MethodHandles.Lookup.html#lookups">查找工厂方法</a>之一，
 *     如{@link Lookup#findVirtual Lookup.findVirtual}，
 *     将符号引用解析为方法句柄。
 *     符号引用由类、名称字符串和类型组成。
 * <li>通过调用工厂方法{@link Lookup#unreflect Lookup.unreflect}
 *     或{@link Lookup#unreflectSpecial Lookup.unreflectSpecial}
 *     将{@link Method}转换为方法句柄。
 * <li>通过调用工厂方法{@link Lookup#unreflectConstructor Lookup.unreflectConstructor}
 *     将{@link Constructor}转换为方法句柄。
 * <li>通过调用工厂方法{@link Lookup#unreflectGetter Lookup.unreflectGetter}
 *     或{@link Lookup#unreflectSetter Lookup.unreflectSetter}
 *     将{@link Field}转换为方法句柄。
 * </ul>
 *
 * <h1>分解限制</h1>
 * 给定合适的{@code Lookup}对象，可以分解任何直接方法句柄
 * 以恢复底层方法、构造函数或字段的符号引用。
 * 分解必须通过等效于创建目标方法句柄的{@code Lookup}对象，
 * 或具有足够访问权限来重新创建等效方法句柄的对象来完成。
 * <p>
 * 如果底层方法是<a href="MethodHandles.Lookup.html#callsens">调用者敏感的</a>，
 * 直接方法句柄将被"绑定"到特定的调用者类，即用于创建它的
 * 查找对象的{@linkplain java.lang.invoke.MethodHandles.Lookup#lookupClass() 查找类}。
 * 使用不同的查找类分解此方法句柄将失败，
 * 即使底层方法是公共的（如{@code Class.forName}）。
 * <p>
 * 查找对象匹配的要求为程序提供了"快速失败"行为，
 * 这些程序可能会错误地信任来自意外范围的
 * 带有符号信息（或调用者绑定）的方法句柄的错误揭示。
 * 使用{@link java.lang.invoke.MethodHandles#reflectAs}来覆盖此限制。
 *
 * <h1><a name="refkinds"></a>引用类型</h1>
 * <a href="MethodHandles.Lookup.html#lookups">查找工厂方法</a>
 * 对应于方法、构造函数和字段的所有主要用例。
 * 这些用例可以使用小整数来区分，如下所示：
 * <table border=1 cellpadding=5 summary="引用类型">
 * <tr><th>引用类型</th><th>描述性名称</th><th>范围</th><th>成员</th><th>行为</th></tr>
 * <tr>
 *     <td>{@code 1}</td><td>{@code REF_getField}</td><td>{@code class}</td>
 *     <td>{@code FT f;}</td><td>{@code (T) this.f;}</td>
 * </tr>
 * <tr>
 *     <td>{@code 2}</td><td>{@code REF_getStatic}</td><td>{@code class}或{@code interface}</td>
 *     <td>{@code static}<br>{@code FT f;}</td><td>{@code (T) C.f;}</td>
 * </tr>
 * <tr>
 *     <td>{@code 3}</td><td>{@code REF_putField}</td><td>{@code class}</td>
 *     <td>{@code FT f;}</td><td>{@code this.f = x;}</td>
 * </tr>
 * <tr>
 *     <td>{@code 4}</td><td>{@code REF_putStatic}</td><td>{@code class}</td>
 *     <td>{@code static}<br>{@code FT f;}</td><td>{@code C.f = arg;}</td>
 * </tr>
 * <tr>
 *     <td>{@code 5}</td><td>{@code REF_invokeVirtual}</td><td>{@code class}</td>
 *     <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
 * </tr>
 * <tr>
 *     <td>{@code 6}</td><td>{@code REF_invokeStatic}</td><td>{@code class}或{@code interface}</td>
 *     <td>{@code static}<br>{@code T m(A*);}</td><td>{@code (T) C.m(arg*);}</td>
 * </tr>
 * <tr>
 *     <td>{@code 7}</td><td>{@code REF_invokeSpecial}</td><td>{@code class}或{@code interface}</td>
 *     <td>{@code T m(A*);}</td><td>{@code (T) super.m(arg*);}</td>
 * </tr>
 * <tr>
 *     <td>{@code 8}</td><td>{@code REF_newInvokeSpecial}</td><td>{@code class}</td>
 *     <td>{@code C(A*);}</td><td>{@code new C(arg*);}</td>
 * </tr>
 * <tr>
 *     <td>{@code 9}</td><td>{@code REF_invokeInterface}</td><td>{@code interface}</td>
 *     <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
 * </tr>
 * </table>
 * @since 1.8
 */
public
interface MethodHandleInfo {
    /**
     * 直接方法句柄引用类型，
     * 如<a href="MethodHandleInfo.html#refkinds">上表</a>中定义的。
     */
    public static final int
        REF_getField                = Constants.REF_getField,
        REF_getStatic               = Constants.REF_getStatic,
        REF_putField                = Constants.REF_putField,
        REF_putStatic               = Constants.REF_putStatic,
        REF_invokeVirtual           = Constants.REF_invokeVirtual,
        REF_invokeStatic            = Constants.REF_invokeStatic,
        REF_invokeSpecial           = Constants.REF_invokeSpecial,
        REF_newInvokeSpecial        = Constants.REF_newInvokeSpecial,
        REF_invokeInterface         = Constants.REF_invokeInterface;

    /**
     * 返回分解的方法句柄的引用类型，这反过来
     * 确定方法句柄的底层成员是构造函数、方法还是字段。
     * 有关定义，请参见<a href="MethodHandleInfo.html#refkinds">上表</a>。
     * @return 用于访问底层成员的引用类型的整数代码
     */
    public int getReferenceKind();

    /**
     * 返回定义分解的方法句柄的底层成员的类。
     * @return 底层成员的声明类
     */
    public Class<?> getDeclaringClass();

    /**
     * 返回分解的方法句柄的底层成员的名称。
     * 如果底层成员是构造函数，则为{@code "<init>"}，
     * 否则为简单的方法名或字段名。
     * @return 底层成员的简单名称
     */
    public String getName();

    /**
     * 返回分解的符号引用的名义类型，表示为方法类型。
     * 如果引用是构造函数，返回类型将是{@code void}。
     * 如果是非静态方法，方法类型将不提及{@code this}参数。
     * 如果是字段且请求的访问是读取字段，
     * 方法类型将没有参数并返回字段类型。
     * 如果是字段且请求的访问是写入字段，
     * 方法类型将有一个字段类型的参数并返回{@code void}。
     * <p>
     * 注意原始直接方法句柄可能包含前导{@code this}参数，
     * 或者（在构造函数的情况下）将{@code void}返回类型
     * 替换为构造的类。
     * 名义类型不包含任何{@code this}参数，
     * 并且（在构造函数的情况下）将返回{@code void}。
     * @return 底层成员的类型，表示为方法类型
     */
    public MethodType getMethodType();

    // Utility methods.
    // NOTE: class/name/type and reference kind constitute a symbolic reference
    // member and modifiers are an add-on, derived from Core Reflection (or the equivalent)

    /**
     * Reflects the underlying member as a method, constructor, or field object.
     * If the underlying member is public, it is reflected as if by
     * {@code getMethod}, {@code getConstructor}, or {@code getField}.
     * Otherwise, it is reflected as if by
     * {@code getDeclaredMethod}, {@code getDeclaredConstructor}, or {@code getDeclaredField}.
     * The underlying member must be accessible to the given lookup object.
     * @param <T> the desired type of the result, either {@link Member} or a subtype
     * @param expected a class object representing the desired result type {@code T}
     * @param lookup the lookup object that created this MethodHandleInfo, or one with equivalent access privileges
     * @return a reference to the method, constructor, or field object
     * @exception ClassCastException if the member is not of the expected type
     * @exception NullPointerException if either argument is {@code null}
     * @exception IllegalArgumentException if the underlying member is not accessible to the given lookup object
     */
    public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup);

    /**
     * Returns the access modifiers of the underlying member.
     * @return the Java language modifiers for underlying member,
     *         or -1 if the member cannot be accessed
     * @see Modifier
     * @see #reflectAs
     */
    public int getModifiers();

    /**
     * Determines if the underlying member was a variable arity method or constructor.
     * Such members are represented by method handles that are varargs collectors.
     * @implSpec
     * This produces a result equivalent to:
     * <pre>{@code
     *     getReferenceKind() >= REF_invokeVirtual && Modifier.isTransient(getModifiers())
     * }</pre>
     *
     *
     * @return {@code true} if and only if the underlying member was declared with variable arity.
     */
    // spelling derived from java.lang.reflect.Executable, not MethodHandle.isVarargsCollector
    public default boolean isVarArgs()  {
        // fields are never varargs:
        if (MethodHandleNatives.refKindIsField((byte) getReferenceKind()))
            return false;
        // not in the public API: Modifier.VARARGS
        final int ACC_VARARGS = 0x00000080;  // from JVMS 4.6 (Table 4.20)
        assert(ACC_VARARGS == Modifier.TRANSIENT);
        return Modifier.isTransient(getModifiers());
    }

    /**
     * Returns the descriptive name of the given reference kind,
     * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
     * The conventional prefix "REF_" is omitted.
     * @param referenceKind an integer code for a kind of reference used to access a class member
     * @return a mixed-case string such as {@code "getField"}
     * @exception IllegalArgumentException if the argument is not a valid
     *            <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
     */
    public static String referenceKindToString(int referenceKind) {
        if (!MethodHandleNatives.refKindIsValid(referenceKind))
            throw newIllegalArgumentException("invalid reference kind", referenceKind);
        return MethodHandleNatives.refKindName((byte)referenceKind);
    }

    /**
     * Returns a string representation for a {@code MethodHandleInfo},
     * given the four parts of its symbolic reference.
     * This is defined to be of the form {@code "RK C.N:MT"}, where {@code RK} is the
     * {@linkplain #referenceKindToString reference kind string} for {@code kind},
     * {@code C} is the {@linkplain java.lang.Class#getName name} of {@code defc}
     * {@code N} is the {@code name}, and
     * {@code MT} is the {@code type}.
     * These four values may be obtained from the
     * {@linkplain #getReferenceKind reference kind},
     * {@linkplain #getDeclaringClass declaring class},
     * {@linkplain #getName member name},
     * and {@linkplain #getMethodType method type}
     * of a {@code MethodHandleInfo} object.
     *
     * @implSpec
     * This produces a result equivalent to:
     * <pre>{@code
     *     String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type)
     * }</pre>
     *
     * @param kind the {@linkplain #getReferenceKind reference kind} part of the symbolic reference
     * @param defc the {@linkplain #getDeclaringClass declaring class} part of the symbolic reference
     * @param name the {@linkplain #getName member name} part of the symbolic reference
     * @param type the {@linkplain #getMethodType method type} part of the symbolic reference
     * @return a string of the form {@code "RK C.N:MT"}
     * @exception IllegalArgumentException if the first argument is not a valid
     *            <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
     * @exception NullPointerException if any reference argument is {@code null}
     */
    public static String toString(int kind, Class<?> defc, String name, MethodType type) {
        Objects.requireNonNull(name); Objects.requireNonNull(type);
        return String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type);
    }
}
